from django.core.exceptions import ValidationError
from .models import Book, Author, BookInstance, Genre
from django.views import View
from django.utils.translation import gettext as _
from django.views.generic import ListView, DeleteView, UpdateView, CreateView
from django.db.models import Q
from django.contrib.auth import logout
from django.shortcuts import render, get_object_or_404, redirect
from django.contrib.auth.mixins import LoginRequiredMixin, PermissionRequiredMixin
from django.urls import reverse_lazy
from django.views import generic
import datetime
from django.http import HttpResponseRedirect
from django.urls import reverse
from catalog.forms import RenewBookForm
from django.forms import ModelForm
from django.contrib.auth.decorators import login_required, permission_required

from django.views.generic import CreateView
from .models import Author

class AuthorCreate(CreateView):  # 必须继承自CreateView或其他CBV
    model = Author
    fields = ['first_name', 'last_name', 'date_of_birth', 'date_of_death']
    template_name = 'catalog/author_form.html'

class AuthorUpdate(PermissionRequiredMixin, UpdateView):
    model = Author
    fields = '__all__'
    permission_required = 'catalog.change_author'

class AuthorDelete(PermissionRequiredMixin, DeleteView):
    model = Author
    success_url = reverse_lazy('authors')
    permission_required = 'catalog.delete_author'

    def form_valid(self, form):
        try:
            self.object.delete()
            return HttpResponseRedirect(self.success_url)
        except Exception as e:
            return HttpResponseRedirect(
                reverse("author-delete", kwargs={"pk": self.object.pk})
            )

class RenewBookModelForm(ModelForm):
    def clean_due_back(self):
        data = self.cleaned_data['due_back']

        if data < datetime.date.today():
            raise ValidationError(_('Invalid date - renewal in past'))

        if data > datetime.date.today() + datetime.timedelta(weeks=4):
            raise ValidationError(_('Invalid date - renewal more than 4 weeks ahead'))

        return data

    class Meta:
        model = BookInstance
        fields = ['due_back']
        labels = {'due_back': _('Renewal date')}
        help_texts = {'due_back': _('Enter a date between now and 4 weeks (default 3).')}

@login_required
@permission_required('catalog.can_mark_returned', raise_exception=True)
def renew_book_librarian(request, pk):
    """View function for renewing a specific BookInstance by librarian."""
    book_instance = get_object_or_404(BookInstance, pk=pk)

    if request.method == 'POST':
        form = RenewBookForm(request.POST)
        if form.is_valid():
            book_instance.due_back = form.cleaned_data['renewal_date']
            book_instance.save()
            return HttpResponseRedirect(reverse('all-borrowed'))
    else:
        proposed_renewal_date = datetime.date.today() + datetime.timedelta(weeks=3)
        form = RenewBookForm(initial={'renewal_date': proposed_renewal_date})

    context = {
        'form': form,
        'book_instance': book_instance,
    }

    return render(request, 'catalog/book_renew_librarian.html', context)

class BookDelete(PermissionRequiredMixin, DeleteView):
    model = Book
    success_url = reverse_lazy('catalog:book_list')
    permission_required = 'catalog.delete_book'

    def delete(self, request, *args, **kwargs):
        # 考虑使用级联删除或软删除而不是直接删除
        book = self.get_object()
        book.bookinstance_set.all().delete()
        return super().delete(request, *args, **kwargs)

def all_borrowed(request):
    borrowed_books = BookInstance.objects.filter(status__exact='o').order_by('due_back')
    return render(request, 'catalog/borrowed_books.html', {'borrowed_books': borrowed_books})

class LoanedBooksByUserListView(LoginRequiredMixin, generic.ListView):
    """Generic class-based view listing books on loan to current user."""
    model = BookInstance
    template_name = 'catalog/bookinstance_list_borrowed_user.html'
    paginate_by = 10

    def get_queryset(self):
        return BookInstance.objects.filter(
            borrower=self.request.user,
            status__exact='o'
        ).order_by('due_back')

def index(request):
    """View function for home page of site."""
    num_authors = Author.objects.count()
    num_visits = request.session.get('num_visits', 0)
    num_visits += 1
    request.session['num_visits'] = num_visits

    search_word = "fiction"
    num_genres = Genre.objects.filter(name__icontains=search_word).count()
    num_books = Book.objects.filter(title__icontains=search_word).count()
    num_instances_available = BookInstance.objects.filter(status__exact='a').count()
    num_instances = BookInstance.objects.all().count()

    context = {
        'num_genres': num_genres,
        'num_books': num_books,
        'num_instances_available': num_instances_available,
        'num_instances': num_instances,
        'num_authors': num_authors,
        'search_word': search_word,
    }

    return render(request, 'index.html', context=context)

def book_detail_view(request, primary_key):
    book = get_object_or_404(Book, pk=primary_key)
    return render(request, 'catalog/book_detail.html', context={'book': book})

class BookListView(generic.ListView):
    model = Book
    template_name = 'books/book_list.html'
    context_object_name = 'book_list'
    paginate_by = 10

    def get_queryset(self):
        queryset = super().get_queryset()
        search_term = self.request.GET.get('search', '')

        if search_term:
            try:
                search_id = int(search_term)
                queryset = queryset.filter(
                    Q(title__icontains=search_term) |
                    Q(author_id=search_id)
                )
            except ValueError:
                queryset = queryset.filter(title__icontains=search_term)
        return queryset

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['search_term'] = self.request.GET.get('search', '')
        return context

class BookDetailView(generic.DetailView):
    model = Book
    paginate_by = 10

class MyView(PermissionRequiredMixin, View):
    permission_required = ('catalog.can_mark_returned', 'catalog.change_book')

class AllBorrowedBooksListView(PermissionRequiredMixin, ListView):
    model = BookInstance
    template_name = 'catalog/borrowed_books.html'
    permission_required = 'catalog.can_mark_returned'
    login_url = '/accounts/login/'

    def get_queryset(self):
        return BookInstance.objects.filter(status__exact='o').order_by('due_back')

class AuthorListView(ListView):
    model = Author
    template_name = 'author_list.html'
    context_object_name = 'author-list'

def logout_view(request):
    logout(request)
    return redirect('index')